#ifndef _ALGO_MATRIX_H_
#define _ALGO_MATRIX_H_


#include "ct_type.h"
#include "algo_qfp16.h"

#define MATRIX_ROW    2
#define MATRIX_COLUMN 2
typedef struct {
    int16_t Mdat[MATRIX_ROW][MATRIX_COLUMN];
} Matrix_t;


typedef struct {
    qFP16_t Mdat[MATRIX_ROW][MATRIX_COLUMN];
} Matrix_fp16_t;


// 定义矩阵操作的函数指针类型
typedef void(code *mat_zero_func_t)(void *r);
typedef void(code *mat_setup_func_t)(void *r, float value);
typedef void(code *mat_add_func_t)(void *r, void *a, void *b);
typedef void(code *mat_sub_func_t)(void *r, void *a, void *b);
typedef void(code *mat_scal_mult_func_t)(void *r, float k, void *a);
typedef void(code *mat_mult_func_t)(void *r, void *a, void *b);
typedef void(code *mat_transpose_func_t)(void *result, void *input);
typedef void(code *mat_identity_func_t)(void *result);
typedef void(code *mat_inverse_func_t)(void *result, void *input);
typedef void(code *array_to_matrix_func_t)(void *mat, const float *array);
typedef void(code *mat_print_func_t)(void *m);

// 定义整数矩阵操作的结构体
typedef struct {
    mat_zero_func_t        mat_zero;
    mat_setup_func_t       mat_setup;
    mat_add_func_t         mat_add;
    mat_sub_func_t         mat_sub;
    mat_scal_mult_func_t   mat_scal_mult;
    mat_mult_func_t        mat_mult;
    mat_transpose_func_t   mat_transpose;
    mat_identity_func_t    mat_identity;
    mat_inverse_func_t     mat_inverse;
    array_to_matrix_func_t array_to_matrix;
    mat_print_func_t       mat_print;
} MatrixOps_t;

// 定义固定点矩阵操作的结构体
typedef struct {
    mat_zero_func_t        qFP16_mat_zero;
    mat_setup_func_t       qFP16_mat_setup;
    mat_add_func_t         qFP16_mat_add;
    mat_sub_func_t         qFP16_mat_sub;
    mat_scal_mult_func_t   qFP16_mat_scal_mult;
    mat_mult_func_t        qFP16_mat_mult;
    mat_transpose_func_t   qFP16_mat_transpose;
    mat_identity_func_t    qFP16_mat_identity;
    mat_inverse_func_t     qFP16_mat_inverse;
    array_to_matrix_func_t qFP16_array_to_matrix;
    mat_print_func_t       qFP16_mat_print;
} MatrixFPOps_t;


/**
 * @brief Sets all elements of a matrix to zero.
 *
 * This function iterates over all elements of the matrix and sets each to zero.
 * It assumes that the matrix is a square matrix of size defined by MATRIX_SIZE.
 *
 * @param r Pointer to the matrix that will be set to zero.
 */
void mat_zero(Matrix_t *r);
void qFP16_mat_zero(Matrix_fp16_t *r);

/**
 * @brief init matrix
 * @param m
 * @param value
 */
void mat_setup(Matrix_t *m, int value);
void qFP16_mat_setup(Matrix_fp16_t *r, float value);

/**
 * @brief copy matrix
 * @param r
 * @param a
 */
void mat_copy(Matrix_t *r, Matrix_t *a);
void qFP16_mat_copy(Matrix_fp16_t *r, Matrix_fp16_t *a);

/**
 * @brief Performs matrix addition.
 *
 * This function adds two matrices element-wise.
 *
 * @param r Pointer to the resultant matrix.
 * @param a Pointer to the first input matrix.
 * @param b Pointer to the second input matrix.
 */
void mat_add(Matrix_t *r, Matrix_t *a, Matrix_t *b);

void qFP16_mat_add(Matrix_fp16_t *r, Matrix_fp16_t *a, Matrix_fp16_t *b);

/**
 * @brief Performs matrix subtraction.
 *
 * This function subtracts the second matrix from the first matrix element-wise.
 *
 * @param r Pointer to the resultant matrix.
 * @param a Pointer to the first input matrix.
 * @param b Pointer to the second input matrix.
 */
void mat_sub(Matrix_t *r, Matrix_t *a, Matrix_t *b);
void qFP16_mat_sub(Matrix_fp16_t *r, Matrix_fp16_t *a, Matrix_fp16_t *b);

/**
 * @brief Performs scalar multiplication on a matrix.
 *
 * This function multiplies each element of a matrix by a scalar.
 *
 * @param r Pointer to the resultant matrix.
 * @param k Scalar to multiply.
 * @param a Pointer to the input matrix.
 */
void mat_scal_mult(Matrix_t *r, Matrix_t *a, int k);
void qFP16_mat_scal_mult(Matrix_fp16_t *r, Matrix_fp16_t *a, float k);

/**
 * @brief Performs matrix multiplication.
 *
 * This function multiplies two matrices.
 *
 * @param r Pointer to the resultant matrix.
 * @param a Pointer to the first input matrix.
 * @param b Pointer to the second input matrix.
 */
void mat_mult(Matrix_t *r, Matrix_t *a, Matrix_t *b);
void qFP16_mat_mult(Matrix_fp16_t *r, Matrix_fp16_t *a, Matrix_fp16_t *b);

/**
 * @brief Calculates the transpose of a matrix.
 *
 * This function calculates the transpose of a given matrix.
 *
 * @param result Pointer to the resultant matrix.
 * @param input Pointer to the input matrix.
 */
void mat_transpose(Matrix_t *result, Matrix_t *input);
void qFP16_mat_transpose(Matrix_fp16_t *result, Matrix_fp16_t *input);

/**
 * @brief Creates an identity matrix.
 *
 * This function creates an identity matrix of given size.
 *
 * @param result Pointer to the resultant matrix.
 */
void mat_identity(Matrix_t *result);
void qFP16_mat_identity(Matrix_fp16_t *result);

/**
 * @brief Calculates the inverse of a matrix.
 *
 * This function calculates the inverse of a given matrix. If the matrix is not
 * invertible, the function does nothing.
 *
 * @param result Pointer to the resultant matrix.
 * @param input Pointer to the input matrix.
 */
void mat_inverse(Matrix_t *result, Matrix_t *input);
void mat_inverse_fp16(Matrix_t *result, Matrix_t *input);
void qFP16_mat_inverse(Matrix_fp16_t *result, Matrix_fp16_t *input);


/**
 * @brief Converts a one-dimensional array to a Matrix structure.
 *
 * This function takes a one-dimensional array representing a matrix in row-major order
 * and converts it into a Matrix structure. The number of rows and columns of the matrix
 * must be specified.
 *
 * @param mat Pointer to the resultant Matrix structure.
 * @param array Pointer to the one-dimensional array.
 */
void array_to_matrix(Matrix_t *mat, const float *array);
void qFP16_array_to_matrix(Matrix_fp16_t *mat, const float *array);

/**
 * @brief Prints a matrix.
 *
 * This function prints a given matrix to the standard output.
 *
 * @param m Pointer to the matrix to print.
 */
void mat_print(Matrix_t *m);
void qFP16_mat_print(Matrix_fp16_t *m);

void matrix_test(void);

#endif    // _ALGO_MATRIX_H_